package cn.rojao.wx.config.shiro;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.authc.AnonymousFilter;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.apache.shiro.web.filter.authc.LogoutFilter;
import org.apache.shiro.web.filter.authc.UserFilter;
import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.filter.DelegatingFilterProxy;

@Configuration
public class ShiroConfig {
	
	 private static final Map<String, String> FILTER_CHAIN_DEFINITION_MAP = new LinkedHashMap<String, String>();
	
	/**
	 * FilterRegistrationBean
	 * @return
	 */
	@Bean
	public FilterRegistrationBean filterRegistrationBean() {
		FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter")); 
        filterRegistration.setEnabled(true);
        filterRegistration.addUrlPatterns("/*"); 
        filterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
        return filterRegistration;
	}
	
	/*@Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager()
    {
        MemoryConstrainedCacheManager cacheManager = new MemoryConstrainedCacheManager();
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setCacheManager(cacheManager);
        defaultWebSecurityManager.setRealm(jdbcRealm());

        return defaultWebSecurityManager;
    }*/
	
	   @Bean(name = "jdbcRealm")
	    @DependsOn("lifecycleBeanPostProcessor")
	    public JdbcRealm jdbcRealm()
	    {
	        JdbcRealm jdbcRealm = new ShiroRealm();
	 /*       jdbcRealm.setAuthenticationQuery("SELECT password, salt FROM user WHERE email = ?");
	        jdbcRealm.setPermissionsLookupEnabled(true);
	        jdbcRealm.setUserRolesQuery("select roleName from userrole where email = ?");
	        jdbcRealm.setPermissionsQuery("select permission from rolespermission where roleName = ?");*/
	        HashedCredentialsMatcher hashedCredentialMatcher = new HashedCredentialsMatcher();
	        hashedCredentialMatcher.setHashAlgorithmName("SHA-256");
	        hashedCredentialMatcher.setHashIterations(1024);
	        hashedCredentialMatcher.setStoredCredentialsHexEncoded(false);
	        jdbcRealm.setCredentialsMatcher(hashedCredentialMatcher);
	        jdbcRealm.init();

	        return jdbcRealm;
	    }
	
	/**
	 * @see org.apache.shiro.spring.web.ShiroFilterFactoryBean
	 * @return
	 */
	@Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setUnauthorizedUrl("/forbidden");
        FILTER_CHAIN_DEFINITION_MAP.put("/", "anon");
        FILTER_CHAIN_DEFINITION_MAP.put("/static/**", "anon");
        FILTER_CHAIN_DEFINITION_MAP.put("/login", "authc");
      //  FILTER_CHAIN_DEFINITION_MAP.put("/login/checkUser", "authc");
     //   FILTER_CHAIN_DEFINITION_MAP.put("/index", "anon");
        FILTER_CHAIN_DEFINITION_MAP.put("/**", "user,roles[admin]");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(FILTER_CHAIN_DEFINITION_MAP);
        Map<String, Filter> servletFilters = new HashMap<String, Filter>();
        servletFilters.put("anon", new AnonymousFilter());
        servletFilters.put("authc", new FormAuthFilter());
        servletFilters.put("logout", new LogoutFilter());
        servletFilters.put("roles", new RolesAuthorizationFilter());
        servletFilters.put("user", new UserFilter());
        shiroFilterFactoryBean.setFilters(servletFilters);

        return shiroFilterFactoryBean;
    }
	
	/**
	 * @see org.apache.shiro.mgt.SecurityManager
	 * @return
	 */
	@Bean(name="securityManager")
	public DefaultWebSecurityManager securityManager() {
		DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
		manager.setRealm(userRealm());
		manager.setCacheManager(cacheManager());
		manager.setSessionManager(defaultWebSessionManager());
		return manager;
	}
	
	/**
	 * @see DefaultWebSessionManager
	 * @return
	 */
	@Bean(name="sessionManager")
	public DefaultWebSessionManager defaultWebSessionManager() {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		sessionManager.setCacheManager(cacheManager());
		sessionManager.setGlobalSessionTimeout(1800000);
		sessionManager.setDeleteInvalidSessions(true);
		sessionManager.setSessionValidationSchedulerEnabled(true);
		sessionManager.setDeleteInvalidSessions(true);
		return sessionManager;
	}
	
	/**
	 * @see UserRealm--->AuthorizingRealm
	 * @return
	 */
	@Bean
	@DependsOn(value="lifecycleBeanPostProcessor")
	public UserRealm userRealm() {
		UserRealm userRealm = new UserRealm();
	//	userRealm.setCacheManager(cacheManager());
		return userRealm;
	}
	
	@Bean
	public URLPermissionsFilter urlPermissionsFilter() {
		return new URLPermissionsFilter();
	}
	
	@Bean
	public EhCacheManager cacheManager() {
		EhCacheManager cacheManager = new EhCacheManager();
		cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
		return cacheManager;
	}
	
	@Bean
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}
}